import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";
import HavokPhysics from "@babylonjs/havok";
import {
    Engine,
    Scene,
    ArcRotateCamera,
    Vector3,
    Color3,
    HemisphericLight,
    HavokPlugin,
    StandardMaterial,
    CubeTexture,
    Texture,
    MeshBuilder,
    PBRMaterial,
    HDRCubeTexture,
    CreateBox
} from "@babylonjs/core";
import { createGround } from "./createGround";
import { createNewtonCradle } from "./createNewtonCradle";
import { createNewtonCradle2 } from "./createNewtonCradle2";
import { testHingeConstraint } from "./testHingeConstraint";
import { testPhysicsShapeContainer } from "./testPhysicsShapeContainer";

async function initCanvas() {
    var app = document.getElementById("app")!;
    app.style.width = "100vw";
    app.style.height = "100vh";
    app.style.overflow = "hidden";
    var canvas = document.createElement("canvas");
    canvas.style.width = "100%";
    canvas.style.height = "100%";
    canvas.id = "gameCanvas";
    app.appendChild(canvas);
    return canvas;
}

async function initBabylon(canvas: HTMLCanvasElement) {
    var engine = new Engine(canvas, true);
    var scene = new Scene(engine);

    // 定义硬件缩放级别，解决文本不清晰问题
    engine.setHardwareScalingLevel(1 / window.devicePixelRatio);

    return { scene, engine };
}

function initDebugLayer(scene: Scene) {
    window.addEventListener("keydown", (ev) => {
        // Shift+Ctrl+Alt+I
        if (ev.shiftKey && ev.ctrlKey && ev.altKey && ev.keyCode === 73) {
            if (scene.debugLayer.isVisible()) {
                scene.debugLayer.hide();
            } else {
                scene.debugLayer.show();
            }
        }
    });
}

async function initCameraAndLight(canvas: HTMLCanvasElement, scene: Scene) {
    var camera: ArcRotateCamera = new ArcRotateCamera(
        "Camera",
        0,
        Math.PI / 2,
        25,
        Vector3.Zero(),
        scene
    );
    camera.attachControl(canvas, true);
    new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
}

async function initPhysics(scene: Scene) {
    // 启用物理引擎
    const gravityVector = new Vector3(0, -9.81, 0);
    // const gravityVector = new Vector3(0, -9.81, 0);
    const havokInstance = await HavokPhysics({
        locateFile: () => {
            return "./HavokPhysics.wasm";
        }
    });
    const physicsPlugin = new HavokPlugin(false, havokInstance);
    scene.enablePhysics(gravityVector, physicsPlugin);
    return physicsPlugin;
}

function createSkyBox(scene: Scene) {
    // 环境纹理，用于材质反射
    // https://doc.babylonjs.com/features/featuresDeepDive/materials/using/HDREnvironment/#creating-a-compressed-environment-texture-using-the-sandbox
    // env 文件制作沙箱 https://sandbox.babylonjs.com/
    // public/textures/PBR_Spheres.glb 拖入沙箱，再拖入一个 hdr 纹理，然后导出
    scene.environmentTexture = new CubeTexture("./textures/environment.env", scene);

    // // 使用 HDR 天空盒
    // const hdrTexture = new HDRCubeTexture(
    //     "./textures/kloofendal_48d_partly_cloudy_puresky_4k.hdr",
    //     scene,
    //     1024
    // );

    // // Skybox
    // var hdrSkyBox = CreateBox("hdrSkyBox", { size: 1000.0 }, scene);
    // var hdrSkyboxMaterial = new PBRMaterial("skyBox", scene);
    // hdrSkyboxMaterial.backFaceCulling = false;
    // hdrSkyboxMaterial.reflectionTexture = hdrTexture.clone();
    // hdrSkyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
    // hdrSkyboxMaterial.microSurface = 1; // 细节、模糊度
    // hdrSkyboxMaterial.environmentIntensity = 1; // 环境光强度
    // hdrSkyboxMaterial.cameraExposure = 1; // 曝光度
    // hdrSkyboxMaterial.cameraContrast = 1; // 对比度
    // hdrSkyboxMaterial.disableLighting = true;
    // hdrSkyBox.material = hdrSkyboxMaterial;
    // hdrSkyBox.infiniteDistance = true;

    // 使用 SkyBox 天空盒
    var skybox = MeshBuilder.CreateBox("skyBox", { size: 1000.0 }, scene);
    skybox.rotate(Vector3.Up(), -(17 * Math.PI) / 6);
    var skyboxMaterial = new StandardMaterial("skyBox", scene);
    skyboxMaterial.backFaceCulling = false;
    // 天空盒图片路径需要定位到文件夹内
    // 例如图片路径在 textures/TropicalSunnyDay/TropicalSunnyDay_nx.jpg
    // 就要定位到 textures/TropicalSunnyDay/TropicalSunnyDay
    skyboxMaterial.reflectionTexture = new CubeTexture(
        "./textures/TropicalSunnyDay/TropicalSunnyDay",
        scene
    );
    skyboxMaterial.reflectionTexture.coordinatesMode = Texture.SKYBOX_MODE;
    skyboxMaterial.disableLighting = true;
    skybox.material = skyboxMaterial;
}

async function createObjects(scene: Scene, physicsPlugin: HavokPlugin) {
    await createNewtonCradle2(scene, physicsPlugin);
    // await testHingeConstraint(scene);
    // await testPhysicsShapeContainer(scene);
}

(async function init() {
    const canvas = await initCanvas();
    const { scene, engine } = await initBabylon(canvas);
    const physicsPlugin = await initPhysics(scene);
    await initCameraAndLight(canvas, scene);
    await createObjects(scene, physicsPlugin);
    initDebugLayer(scene);
    createSkyBox(scene);

    scene.getPhysicsEngine()?.setSubTimeStep(1);
    scene.getPhysicsEngine()?.setTimeStep(1 / 360);

    engine.runRenderLoop(() => {
        scene.render();
    });

    window.addEventListener("resize", function () {
        engine.resize();
    });
})();
